#ifndef __USERSIGNUPSECTION2_H__
#define __USERSIGNUPSECTION2_H__

#include "TcpConnection.h"
#include "Logger.h"
#include "Packet.h"
#include "TLV.h"
#include "YesCrypt.h"
#include "MySQLClient.h"
#include <string.h>

using namespace myNameSpace;

void hexDump(const char* data, int size) {
    for (int i = 0; i < size; i++) {
        printf("%02X ", (unsigned char)data[i]);
        if ((i + 1) % 16 == 0) printf("\n");
    }
    printf("\n");
}

class UserSignupSection2 {
public:
    UserSignupSection2(const Packet &packet, shared_ptr<TcpConnection> pTcpConnection, MySQLClient &mysqlClient): _packet(packet), _pTcpConnection(pTcpConnection), _mysqlClient(mysqlClient) {}

    void process() {
        moqi::LOG_INFO("Thread %u: UserSignupSection2.", pthread_self());
        hexDump(_packet._msg.c_str(), _packet._msg.size());
        const char *msg = _packet._msg.c_str();
        // 1. 解析用户名、密文
        const char *p = msg;
        int userNameLength = 0;
        memcpy(&userNameLength, p, sizeof(int)); // userName长度
        p += sizeof(int);
        char userName[100] = {0};
        memcpy(userName, p, userNameLength); // userName
        p += userNameLength;
        printf("userName: %s, userNameLength: %d\n", userName, userNameLength);
        int encrytedPasswordLength = 0;
        memcpy(&encrytedPasswordLength, p, sizeof(int)); // encrytedPassword长度
        p += sizeof(int);
        char encrytedPassword[1024] = {0};
        memcpy(encrytedPassword, p, encrytedPasswordLength); // encrytedPassword
        printf("encrytedPassword: %s, encrytedPasswordLength: %d\n", encrytedPassword, encrytedPasswordLength);
        // 2.1 若该用户名在数据库中已存在，返回error报文
        TLV response;
        if (_mysqlClient.isExist("monitor_client", "client_name", userName)) {
            char buf[160] = {0};
            sprintf(buf, "User %s already exists.", userName);
            moqi::LOG_WARN(buf);
            response._type = TASK_SIGNUP_SECTION2_RESP_ERROR;
            response._length = strlen(buf);
            strcpy(response._data, buf);
        }
        // 2.2 若该用户在数据库中不存在
        else {
            // 3.1 从MD5形式的密文中获取setting
            string setting = getMd5Setting(encrytedPassword);
            // 3.2 将用户名、setting、密文（setting+哈希值）存入数据库中
            int id = registerClient(userName, setting, encrytedPassword);
            // 4.1 若存入数据库失败，返回error报文
            if (id == -1) {
                const char *buf = "Register client to database failed.";
                moqi::LOG_ERROR(buf); 
                response._type = TASK_SIGNUP_SECTION2_RESP_ERROR;
                response._length = strlen(buf);
                strcpy(response._data, buf);
            }
            // 4.2 若存入数据库成功，返回该新用户在数据库中的id
            else {
                response._type = TASK_SIGNUP_SECTION2_RESP_OK;
                response._length = sizeof(int);
                memcpy(response._data, &id, sizeof(int));
            }
        }
        _pTcpConnection->sendInLoop(response);
    }

private:
    int registerClient(const string &clientName, const string &clientSetting, const string &clientEncrypt) {
        char sql[512] = {0}; // 确保缓冲区足够大！
        sprintf(sql, "INSERT INTO monitor_client(client_name, client_setting, client_encrypt) VALUES('%s', '%s', '%s');", clientName.c_str(), clientSetting.c_str(), clientEncrypt.c_str());
        bool ret = _mysqlClient.writeOperationQuery(sql);
        if (!ret) {
            return -1;
        }
        string id = _mysqlClient.findData("monitor_client", "client_id", "client_name", clientName);
        if (id.empty()) {
            return -1;
        }
        return std::stoi(id);
    }

private:
    Packet _packet;
    shared_ptr<TcpConnection> _pTcpConnection;
    MySQLClient &_mysqlClient;
};

#endif
